#pragma once
#include "DRay.h"
#include "../DSpace.h"
#include "../DVector3.h"

namespace Skill
{
	namespace Ode
	{		
		namespace Geometries
		{		
			void DRay::CollectManagedMemory()
			{
				_Start = nullptr;
				_Direction = nullptr;
				DGeometry::CollectManagedMemory();
			}

			DRay::DRay(DSpace^ space, dReal length)
				:DGeometry(space)
			{
				dSpaceID s = space?space->_Space() : NULL;
				_SetPointer(dCreateRay(s,length),true);	
				if(_Container)
						_Container->AddSpace(this);
			}

			dReal DRay::Length::get()
			{
				if(IsSpace) return Single::NaN;
				return dGeomRayGetLength(_Geom());
			}
			void DRay::Length::set(dReal value)
			{
				if(IsSpace) return;
				dGeomRaySetLength(_Geom(),value);
			}

			DVector3^ DRay::Start::get()
			{
				if(IsSpace) return nullptr;
				if(!_Start)
					_Start = gcnew DVector3();
				if(!_Direction)
					_Direction = gcnew DVector3();
				dGeomRayGet(_Geom(),_Start->_This,_Direction->_This);
				return _Start;
			}
			void DRay::Start::set(DVector3^ value)
			{
				if(IsSpace) return;
				if(!_Direction)
				{	
					_Direction = gcnew DVector3();
					if(!_Start)
						_Start = gcnew DVector3();									
					dGeomRayGet(_Geom(),_Start->_This,_Direction->_This);
				}
				dGeomRaySet(_Geom(),value->_This[0],value->_This[1],value->_This[2],
					_Direction->_This[0],_Direction->_This[1],_Direction->_This[2]);
			}

			DVector3^ DRay::Direction::get()
			{
				if(IsSpace) return nullptr;
				if(!_Start)
					_Start = gcnew DVector3();
				if(!_Direction)
					_Direction = gcnew DVector3();
				dGeomRayGet(_Geom(),_Start->_This,_Direction->_This);
				return _Direction;
			}
			void DRay::Direction::set(DVector3^ value)
			{
				if(IsSpace) return;
				if(!_Start)
				{	
					_Start = gcnew DVector3();
					if(!_Direction)
						_Direction = gcnew DVector3();									
					dGeomRayGet(_Geom(),_Start->_This,_Direction->_This);
				}
				dGeomRaySet(_Geom(),_Start->_This[0],_Start->_This[1],_Start->_This[2],
					value->_This[0],value->_This[1],value->_This[2]);
			}

			void DRay::Set(dReal px, dReal py, dReal pz,
						dReal dx, dReal dy, dReal dz)
			{
				if(IsSpace) return;
				dGeomRaySet(_Geom() , px,py,pz , dx,dy,dz);
			}
			void DRay::Set(DVector3^ start,DVector3^ direction)
			{
				if(IsSpace) return;
				dGeomRaySet(_Geom(),start->_This[0],start->_This[1],start->_This[2],
					direction->_This[0],direction->_This[1],direction->_This[2]);
			}
			void DRay::Get(DVector3^ %start,DVector3^ %direction)
			{
				if(IsSpace) return;
				dGeomRayGet(_Geom(),start->_This,direction->_This);
			}

			void DRay::SetParams(int firstContact, int backfaceCull)
			{
				if(IsSpace) return;
				dGeomRaySetParams(_Geom(), firstContact, backfaceCull);
			}
			void DRay::GetParams([OutAttribute] int %firstContact, [OutAttribute] int %backfaceCull)
			{
				if(IsSpace) return;
				int f,b;
				dGeomRayGetParams(_Geom(),&f, &b);
				firstContact = f;
				backfaceCull = b;
			}
			int DRay::ClosestHit::get()
			{
				if(IsSpace) return 0;
				return dGeomRayGetClosestHit(_Geom());
			}
			void DRay::ClosestHit::set(int value)
			{
				if(IsSpace) return;
				dGeomRaySetClosestHit(_Geom(),value);
			}
		}
	}
}